package me.dz.dreamcleaner.listener;

import me.dz.dreamcleaner.manager.ItemType;
import me.dz.dreamcleaner.manager.MobsType;
import me.dz.dreamcleaner.manager.WorldManager;
import me.dz.dreamcleaner.utils.LogUtils;
import net.citizensnpcs.api.CitizensAPI;
import org.bukkit.Bukkit;
import org.bukkit.Chunk;
import org.bukkit.Location;
import org.bukkit.World;
import org.bukkit.entity.*;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
import org.bukkit.event.entity.CreatureSpawnEvent;
import org.bukkit.event.entity.EntitySpawnEvent;
import org.bukkit.event.entity.ItemSpawnEvent;
import org.bukkit.scheduler.BukkitRunnable;

import java.util.ArrayList;
import java.util.Collection;

import static me.dz.dreamcleaner.DreamCleaner.*;
import static me.dz.dreamcleaner.utils.MsgUtils.alias;
import static me.dz.dreamcleaner.utils.MsgUtils.getLocation;

public class Event implements Listener {

    public static ArrayList<Chunk> items = new ArrayList<>();
    public static ArrayList<Chunk> mobs = new ArrayList<>();

    @EventHandler
    public void onSpawn(EntitySpawnEvent e){
        if (denseEnable){
            checkItem(e.getEntity());
        }
        if (gatherEnable){
            checkMobs(e.getEntity());
        }
    }

    public static class Spawn implements Listener{
        @EventHandler
        public void onSpawn(ItemSpawnEvent e){
            if (denseEnable){
                checkItem(e.getEntity());
            }
            if (gatherEnable){
                checkMobs(e.getEntity());
            }
        }

        @EventHandler
        public void onSpawn(CreatureSpawnEvent e){
            if (denseEnable){
                checkItem(e.getEntity());
            }
            if (gatherEnable){
                checkMobs(e.getEntity());
            }
        }
    }

    public static void checkMobs(Entity entity){
        World world = entity.getWorld();
        Location loc = entity.getLocation();
        Chunk chunk = loc.getChunk();
        Collection<Entity> entities = WorldManager.getNearbyEntities(loc,gatherScope);
        if (WorldManager.canClear(world,gatherBlackWorld,gatherCheck)
                && !mobs.contains(chunk)){
            if (entities.size() > gatherAmount){
                mobs.add(chunk);
                new BukkitRunnable(){
                    @Override
                    public void run() {
                        mobs.remove(loc.getChunk());
                        if (canMobsClear(entity)){
                            entity.remove();
                        }
                        Collection<Entity> entities = WorldManager.getNearbyEntities(loc,gatherScope);
                        if (gatherAsync){
                            new BukkitRunnable(){
                                @Override
                                public void run() {
                                    Event.runMobs(entity,entities);
                                }
                            }.runTaskAsynchronously(pl);
                        }else {
                            Event.runMobs(entity,entities);
                        }
                    }
                }.runTaskLater(pl,1);
            }
        }
    }

    public static void checkItem(Entity entity){
        World world = entity.getWorld();
        Location loc = entity.getLocation();
        Chunk chunk = loc.getChunk();
        Collection<Entity> entities = WorldManager.getNearbyEntities(loc,denseScope);

        if (WorldManager.canClear(world,denseBlackWorld,denseCheck)
        && !items.contains(chunk)){
            if (entities.size() > denseAmount){
                items.add(chunk);
                new BukkitRunnable(){
                    @Override
                    public void run() {
                        items.remove(loc.getChunk());
                        if (canItemClear(entity)){
                            entity.remove();
                        }
                        Collection<Entity> entities = WorldManager.getNearbyEntities(loc,denseScope);
                        if (denseAsync){
                            new BukkitRunnable(){
                                @Override
                                public void run() {
                                    Event.runItem(entity,entities);
                                }
                            }.runTaskAsynchronously(pl);
                        }else {
                            Event.runItem(entity,entities);
                        }
                    }
                }.runTaskLater(pl,1);
            }
        }
    }

    public static void runMobs(Entity source,Collection<Entity> entities){
        Location loc = source.getLocation();
        World world = loc.getWorld();
        assert world != null;
        ArrayList<Player> players = new ArrayList<>();
        StringBuilder builder = new StringBuilder();
        int size = entities.size();
        int total = 0;
        int i = entities.size() - gatherAmount + 8;
        for (Entity entity : entities){
            if (i == 0)break;
            if (entity instanceof Player){
                Player p = (Player) entity;
                if (!citizens || CitizensAPI.getNPCRegistry().getNPC(entity) == null){
                    if (logEnable && logGather)players.add(p);
                    builder.append(p.getName()).append(",");
                }
            }else {
                if (canMobsClear(entity)){
                    total++;
                    new BukkitRunnable(){
                        @Override
                        public void run() {
                            entity.remove();
                        }
                    }.runTask(pl);
                }
            }
            i--;
        }
        if (total > 0){
            int finalTotal = total;
            new BukkitRunnable(){
                @Override
                public void run() {
                    if (size > WorldManager.getNearbyEntities(loc,gatherScope).size()){
                        String msg = gatherMsg
                                .replace("<n>", finalTotal +"")
                                .replace("<prefix>",prefix)
                                .replace("<world>",world.getName())
                                .replace("<name>",alias(world))
                                .replace("<xyz>",getLocation(loc))
                                .replace("<players>",builder.lastIndexOf(",") == -1 ? "" : builder.subSequence(0,builder.lastIndexOf(",")));
                        for (int i = gatherRemind;i > 0;i--){
                            Bukkit.broadcastMessage(msg);
                        }
                    }
                    if (logEnable && logGather) {
                        LogUtils.saveGather(players, loc, finalTotal);
                    }
                }
            }.runTaskLater(pl,1);
        }
    }

    public static void runItem(Entity source,Collection<Entity> entities){
        Location loc = source.getLocation();
        World world = loc.getWorld();
        assert world != null;
        ArrayList<Player> players = new ArrayList<>();
        StringBuilder builder = new StringBuilder();
        int size = entities.size();
        int total = 0;
        int i = entities.size() - denseAmount + 8;
        for (Entity entity : entities){
            if (i == 0)break;
            if (entity instanceof Player){
                Player p = (Player) entity;
                if (!citizens || CitizensAPI.getNPCRegistry().getNPC(entity) == null) {
                    if (logEnable && logDense) players.add(p);
                    builder.append(p.getName()).append(",");
                }
            }else {
                if (canItemClear(entity)){
                    total++;
                    new BukkitRunnable(){
                        @Override
                        public void run() {
                            entity.remove();
                        }
                    }.runTask(pl);
                }
            }
            i--;
        }
        if (total > 0){
            int finalTotal = total;
            new BukkitRunnable(){
                @Override
                public void run() {
                    if (size > WorldManager.getNearbyEntities(loc,denseScope).size()){
                        String msg = denseMsg
                                .replace("<n>", finalTotal +"")
                                .replace("<prefix>",prefix)
                                .replace("<world>",world.getName())
                                .replace("<name>",alias(world))
                                .replace("<xyz>",getLocation(loc))
                                .replace("<players>",builder.lastIndexOf(",") == -1 ? "" : builder.subSequence(0,builder.lastIndexOf(",")));
                        for (int i = denseRemind;i > 0;i--){
                            Bukkit.broadcastMessage(msg);
                        }
                    }
                    if (logEnable && logDense) {
                        LogUtils.saveDense(players, loc, finalTotal);
                    }
                }
            }.runTaskLater(pl,1);
        }
    }

    public static boolean canItemClear(Entity entity){
        for (ItemType type : denseCleaner){
            if (type.canClear(entity)){
                return true;
            }
        }
        return false;
    }

    public static boolean canMobsClear(Entity entity){
        if (citizens){
            if (CitizensAPI.getNPCRegistry().getNPC(entity) != null)return false;
        }
        if (mythicMobs && gatherMythic){
            if (mobsManager.isMythicMobs(entity))return false;
        }
        if (entity instanceof Player)return false;
        if (gatherTameable){
            if (entity instanceof Tameable){
                Tameable tameable = (Tameable) entity;
                if (tameable.isTamed()){
                    return false;
                }
            }
        }
        try {
            if (entity.getCustomName() != null){
                if (gatherCheckName){
                    String name = entity.getCustomName();
                    if (gatherName.size() > 0){
                        if (gatherName.contains(name)){
                            return false;
                        }
                    }
                    if (gatherVagueName.size() > 0){
                        for (String msg : gatherVagueName){
                            if (name.contains(msg)){
                                return false;
                            }
                        }
                    }
                }else {
                    return false;
                }
            }
        }catch (NullPointerException ignored){}
        String name = entity.getType().toString().toUpperCase();
        if (gatherEntity.size() > 0){
            if (gatherEntity.contains(name)){
                return true;
            }
        }
        if (gatherVagueEntity.size() > 0){
            for (String msg : gatherVagueEntity){
                if (name.contains(msg)){
                    return true;
                }
            }
        }
        if (gatherType.size() > 0){
            if (gatherType.contains(name)){
                return false;
            }
        }
        if (gatherVagueType.size() > 0){
            for (String msg : gatherVagueType){
                if (name.contains(msg)){
                    return false;
                }
            }
        }
        for (MobsType type : gatherCleaner){
            if (type.canClear(entity)){
                return true;
            }
        }
        return false;
    }
}
